# -*- coding: utf-8 -*-
import atexit
import sys
import ssl

from pyVim.connect import Disconnect, SmartConnect
from pyVmomi import vim, vmodl
from pyVim.task import WaitForTask

# vcenter信息
vcenter_ip = "172.16.100.57"
vcenter_port = "443"
vcenter_user = "administrator@vsphere.local"
vcenter_pwd = "Shsnc123!@#"
#集群，ZQ-DC01
datacenter_name = "shsnc-datacenter"

# 分配信息
# 要选群集
resource_pool_name = "shsnc-cluster"
# 要选存储，去掉local
datastore_name = "datastore_100.55"
# 要选网络
network_name="VM Network"

vmware_name = "snc-test-imp"
flag = "create"
new_cpu = 2
new_memoryMB = 4096
new_diskGB = 500
# rhel7_64Guest,rhel8_64Guest,ubuntu64Guest
new_guest = "rhel7_64Guest"
# efi/bios
new_firmware = "bios"


# 初始化虚机配置
def create_config_spec(device_change):
    # 创建虚拟机配置
    config = vim.vm.ConfigSpec(deviceChange=device_change)
    # 为配置对象增加配置
    config.name = vmware_name  # 虚拟机名称
    config.numCPUs = new_cpu  # CPU数量
    config.memoryMB = new_memoryMB  # 内存大小，单位为 MB
    config.guestId = new_guest  # 虚拟机的操作系统类型
    config.firmware = new_firmware  # 使用的固件类型
    files = vim.vm.FileInfo()
    files.vmPathName = f"[{datastore_name}]/vm/vmdk/{vmware_name}.vmdk"  # 设置虚拟机文件的存储路径
    config.files = files
    return config


# 配置IP
def create_ip_spec():
    # 创建 IP 设置对象，并指定 IP 地址、子网掩码和网关
    adaptermap = vim.vm.customization.AdapterMapping()
    adaptermap.adapter = vim.vm.customization.IPSettings()
    adaptermap.adapter.ip = vim.vm.customization.FixedIp()
    adaptermap.adapter.ip.ipAddress = '192.168.1.100'  # 指定 IP 地址
    adaptermap.adapter.subnetMask = '255.255.255.0'  # 指定子网掩码
    adaptermap.adapter.gateway = '192.168.1.1'  # 指定网关
    # 如果需要，还可以配置 DNS 服务器和域名
    adaptermap.adapter.dnsDomain = 'yourdomain.com'  # 指定域名
    adaptermap.adapter.dnsServerList = ['8.8.8.8', '8.8.4.4']  # 指定 DNS 服务器
    # 将网卡设置和其他自定义设置组合成自定义规格。
    customspec = vim.vm.customization.Specification(nicSettingMap=[adaptermap])
    # 在克隆虚拟机或重新配置虚拟机时应用自定义规格。
    clonespec = vim.vm.CloneSpec(customization=customspec)


class vCenterManager():
    def __init__(self, vcenter_ip, vcenter_port, vcenter_user, vcenter_pwd):
        self.vcenter_ip = vcenter_ip
        self.vcenter_port = vcenter_port
        self.vcenter_user = vcenter_user
        self.vcenter_pwd = vcenter_pwd
        self.context = None
        self.si = None
        # 建立与vSphere的连接
        if hasattr(ssl, '_create_unverified_context'):
            self.context = ssl._create_unverified_context()
        self.si = SmartConnect(host=self.vcenter_ip, port=self.vcenter_port, user=self.vcenter_user,
                               pwd=self.vcenter_pwd, sslContext=self.context)
        if self.si is None:
            print("请检查vc账号密码")
            sys.exit(1)

        atexit.register(Disconnect, self.si)

    def vm_create(self):
        content = self.si.RetrieveContent()
        # 获取数据中心对象
        datacenter = next((item for item in content.rootFolder.childEntity if item.name == datacenter_name), None)
        # 获取资源池对象
        # resource_pool = content.rootFolder.childEntity[0].resourcePool  # 假设使用第一个资源池
        resource_pool = next(
            (item.resourcePool for item in datacenter.hostFolder.childEntity if item.name == resource_pool_name), None)
        # 待变更列表
        device_change = []

        # #需要创建一个 SCSI 控制器，虚拟硬盘将连接到这个控制器
        # # 创建 SCSI 控制器
        # scsi_controller = vim.vm.device.VirtualSCSIController()
        # scsi_controller.key = -1  # 使用 -1 让 vCenter 自动分配一个 key
        # scsi_controller.sharedBus = vim.vm.device.VirtualSCSIController.Sharing.virtualSharing
        # scsi_controller.scsiCtlrUnitNumber = 0  # SCSI 控制器的单元编号
        # # 添加 SCSI 控制器到设备变更列表
        # device_change.append(vim.vm.device.VirtualDeviceSpec(device=scsi_controller,operation=vim.vm.device.VirtualDeviceSpec.Operation.add))
        #
        # # 创建虚拟硬盘
        # disk = vim.vm.device.VirtualDisk()
        # # 磁盘大小，单位为 KB，这里设置为GB
        # disk.capacityInKB = new_diskGB * 1024 * 1024
        # disk.controllerKey = scsi_controller.key  # 指定控制器的 key
        # disk.unitNumber = 0  # 指定硬盘在控制器上的单元编号
        # # 设置磁盘文件的存储方式
        # disk.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo()
        # disk.backing.diskMode = 'persistent'  # 持久模式
        # disk.backing.split = False
        # #disk.backing.fileName = "[{}] {}.vmdk".format(datastore_name, vmware_name)  # 指定数据存储名称和文件名
        # device_change.append(vim.vm.device.VirtualDeviceSpec(device=disk, operation=vim.vm.device.VirtualDeviceSpec.Operation.add))

        # 创建网卡信息
        nic = vim.vm.device.VirtualVmxnet3()
        nic.deviceInfo = vim.Description()
        nic.deviceInfo.label = "Network Adapter 0"
        nic.deviceInfo.summary = "Network Adapter 0"
        #虚拟网卡的地址类型"assigned" 表示虚拟机的 MAC 地址将由 vSphere 环境自动分配
        nic.addressType = "assigned"
        # 网卡属性: 启用Wake-on-LAN功能
        nic.wakeOnLanEnabled = True
        # 连接属性: 是否在虚拟机启动时连接网卡
        # 设置网卡连接信息
        nic.connectable = vim.vm.device.VirtualDevice.ConnectInfo()
        # 虚拟机启动时连接网卡
        nic.connectable.startConnected = True
        # 允许客人操作系统控制网卡连接状态
        nic.connectable.allowGuestControl = True
        # 指定网卡背板信息，即将网卡连接到哪个网络
        network = None
        net_view = content.viewManager.CreateContainerView(content.rootFolder, [vim.Network], True)
        networks = net_view.view
        net_view.Destroy()  # 记得销毁视图
        for net in networks:
            if net.name == network_name:
                network= net
                break
        if not network:
            raise Exception("Network not found")

        nic.backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo()
        # 将网络对象赋值给背板网络属性
        nic.backing.network = network

        device_change.append(vim.vm.device.VirtualDeviceSpec(device=nic, operation=vim.vm.device.VirtualDeviceSpec.Operation.add))

        # 创建虚拟机
        config = create_config_spec(device_change)
        # task = resource_pool.CreateVM_Task(config=config, pool=resource_pool, host=None)
        task = datacenter.vmFolder.CreateVM_Task(config=config, pool=resource_pool, host=None)
        # 等待任务完成
        try:
            WaitForTask(task)
            print("VM created: %s" % vmware_name)
        except vim.fault.DuplicateName:
            print("VM duplicate name: %s" % vmware_name, file=sys.stderr)
        except vim.fault.AlreadyExists:
            print("VM name %s already exists." % vmware_name, file=sys.stderr)

    def vm_clone(self):
        pass

    def vm_update(self):
        pass


if __name__ == '__main__':
    vc = vCenterManager(vcenter_ip, vcenter_port, vcenter_user, vcenter_pwd)
    if flag == "create":
        vc.vm_create()
    elif flag == "clone":
        vc.vm_clone()
    elif flag == "update":
        vc.vm_update()
    else:
        print("指令错误")
